package org.smartboot.flow.springboot.extension;

import org.smartboot.flow.core.parser.ObjectCreator;
import org.smartboot.flow.manager.reload.Reloader;
import org.smartboot.flow.manager.reload.SqlXmlSelector;
import org.smartboot.flow.manager.reload.XmlParseReloader;
import org.smartboot.flow.manager.reload.XmlSelector;
import org.smartboot.flow.spring.extension.BeanDefinitionVisitor;
import org.smartboot.flow.spring.extension.SpringObjectCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * smart flow reload auto config
 *
 * @author huqiang
 * @since 2022/12/15 16:32
 */
@Configuration
@ConfigurationProperties(prefix = "smart.flow.manage.reload")
@ConditionalOnProperty(name = "smart.flow.manage.reload.enable", havingValue = "true")
public class FlowReloadConfiguration {


    /**
     * Assemble engine after reload.
     */
    private boolean assemble;

    /**
     * Selector datasource config.
     */
    private DataSource datasource;

    /**
     * Selector datasource.
     */
    public static class DataSource {
        private String url;

        /**
         * Ensure driver lib in classpath.
         */
        private String driver;
        private String username;
        private String password;

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getDriver() {
            return driver;
        }

        public void setDriver(String driver) {
            this.driver = driver;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }


    @ConditionalOnProperty(name = "smart.flow.manage.reload.spring-object-creator", havingValue = "true")
    @ConditionalOnMissingBean(ObjectCreator.class)
    @Bean("springObjectCreator")
    public ObjectCreator getSpringObjectCreator(ApplicationContext ctx) {
        SpringObjectCreator soc = new SpringObjectCreator();
        soc.setApplicationContext(ctx);
        return soc;
    }

    @ConditionalOnMissingBean(BeanDefinitionVisitor.class)
    @Bean("beanDefVisitor")
    public BeanDefinitionVisitor getVisitor(ApplicationContext ctx) {
        BeanDefinitionVisitor visitor = new BeanDefinitionVisitor();
        visitor.setBeanFactory(ctx);
        return visitor;
    }

    @ConditionalOnProperty(name = "smart.flow.manage.reload.datasource.url")
    @Bean("xmlSelector")
    public XmlSelector getXmlSelector() {
        SqlXmlSelector selector = new SqlXmlSelector();

        if (this.datasource.getDriver() != null) {
            selector.setDriver(datasource.getDriver());
        }

        selector.setUrl(datasource.getUrl());
        selector.setUsername(datasource.getUsername());
        selector.setPassword(datasource.getPassword());
        return selector;
    }

    @Bean
    @ConditionalOnBean(XmlSelector.class)
    public Reloader getReloader(ApplicationContext ctx) {
        XmlParseReloader reloader = new XmlParseReloader();
        reloader.setAssemble(assemble);

        try {
            ObjectCreator creator = ctx.getBean(ObjectCreator.class);
            reloader.setObjectCreator(creator);
        } catch (Exception ignored) {

        }

        try {
            XmlSelector selector = ctx.getBean(XmlSelector.class);
            reloader.setXmlSelector(selector);
        } catch (Exception ignored) {

        }

        try {
            BeanDefinitionVisitor visitor = ctx.getBean(BeanDefinitionVisitor.class);
            reloader.setVisitor(visitor);
        } catch (Exception ignored) {

        }

        return reloader;
    }

    public void setAssemble(boolean assemble) {
        this.assemble = assemble;
    }

    public void setDatasource(DataSource dataSource) {
        this.datasource = dataSource;
    }
}
